package gate

import (
	"base"
	"emma/protobuf"
	"fmt"
	. "game_server/logic/internal"
	"game_server/logic/player/api"
	"game_server/model"
	"github.com/golang/protobuf/proto"
	"leaf/gate"
	"proto/server/game"
	"proto/server/gate"
	"reflect"
	"time"
)

type gateService struct {
}

func init() {
	service := new(gateService)
	Protocol.Register(new(proto_server_game.Logout), service.logout)
	Protocol.Register(new(proto_server_gate.Request), service.request)
}

func (*gateService) logout(args []interface{}) {
	msg := args[0].(*proto_server_game.Logout)
	base.Logger.Debug("player logout, msg: %s", msg)

	agent := args[1].(gate.Agent)
	if !verifyAgent(agent) {
		return
	}

	playerId := base.PlayerId(msg.PlayerId)
	player_api.Logout(playerId)
}

func (*gateService) request(args []interface{}) {
	msg := args[0].(*proto_server_gate.Request)
	//base.Logger.Debug("player logout, msg: %s", msg)

	agent := args[1].(gate.Agent)
	if !verifyAgent(agent) {
		return
	}

	playerId := base.PlayerId(msg.PlayerId)
	player, exists := player_api.Get(playerId)
	if !exists {
		base.Logger.Debug("player %v not exists", playerId)
		return
	}

	handle := func(player *model.Player, msg *proto_server_gate.Request) (err error) {
		protoName := msg.Name
		player.LogRelease("gate request %s begin", protoName)
		defer func(start time.Time) {
			if r := recover(); r == nil {
				player.LogRelease("gate request %s end, cost time: %s", protoName, time.Since(start))
			} else {
				player.LogError("handle gate request %s error, %s", msg.Name, r)
			}
		}(time.Now())

		method, exists := Service.Get(protoName)
		if !exists {
			err = fmt.Errorf("not %s service.method", protoName)
			return
		}

		protoMsg, exists := protobuf.New(protoName)
		if !exists {
			err = fmt.Errorf("undefined proto message %s", protoName)
			return
		}

		if err = proto.UnmarshalMerge(msg.Data, protoMsg); err != nil {
			return
		}
		player.LogRelease("proto message: %s", protoMsg)

		params := make([]reflect.Value, 0, 2)
		params = append(params, reflect.ValueOf(player))
		params = append(params, reflect.ValueOf(protoMsg))
		err = method.Call(params)

		return
	}

	player.Call(func() {
		if err := handle(player, msg); err != nil {
			player.LogError("handle gate request %s failed, %s", msg.Name, err)
		}
	})
}

func verifyAgent(agent gate.Agent) (result bool) {
	_, result = agent.UserData().(*gateServer)
	if !result {
		base.Logger.Error("invalid gate server agent")
	}

	return
}
